import java.awt.*;
import java.awt.event.*;

import java.net.MalformedURLException;

import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.*;

import java.rmi.server.UnicastRemoteObject;

import javax.swing.*;

import java.text.*;

import java.util.Calendar;
import java.util.*;

public class Server1 extends UnicastRemoteObject implements IServer
{
	// public enum OperationMode { Primary, Secondary };

	// make the timer go off every five seconds
	private static final int TIMER_SPEED = 2000;		
	private static final String DATE_FORMAT = "H:mm:ss";

	// private OperationMode m_mode;
	private String m_mode;
	private String m_data;
	private boolean m_peerAlive;
	private boolean m_stateChanged;

	private int m_connectPort;

	private Calendar m_cal;

	private IServer m_peerServer;

	public Server1(int bindingPort, int connectPort, String mode) throws RemoteException
	{
		System.out.println("Inside ctor");
		m_mode = mode;
		m_connectPort = connectPort;

		try 
		{
			// create a timer to poll the secondary server to ask 
			// if it's alive
			javax.swing.Timer timer = new javax.swing.Timer(TIMER_SPEED, new ClockListener());

			try
			{
				System.out.println("Binding to port...");
				// bind this server to the registry
				Registry reg = LocateRegistry.createRegistry(bindingPort);
				reg.bind("IServer", this);

				System.out.println("foo1");
				System.out.println("Thread sleeping...");
				Thread.sleep(10000); // sleep for 1 min
				System.out.println("Thread woke up...");

				m_peerAlive = true;
				timer.start();
				System.out.println("foo2");
				
				// upon starting up this server, get the state of the other
				// server
				// m_data = m_peerServer.getState();
			}
			catch (RemoteException re)
			{
				System.err.println("re: " + re.getMessage());
				return;
			}
		} 
		catch (Exception e)
		{
			System.err.println("e.getMessage(): " + e.getMessage());
			System.err.println("e.getCause(): " + e.getCause().toString());
			e.printStackTrace(System.out);
			System.err.println("e.getLocalizedMessage(): " + e.getLocalizedMessage());
			return;
		}
	}

	public void doRequest()
	{
	}

	// used if the current server crashes
	public String getMode()
	{
		return m_mode;
	}

	public boolean areYouAlive()
	{
		return true;
	}

	public void notifyChange(String data)
	{
		m_data = data;
		System.out.println(getCurrTime() + ": got data = " + m_data);
	}

	private String getCurrTime()
	{
		Date today = new Date();
		SimpleDateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
		return formatter.format(today);
	}

	public String getState()
	{
		return m_data;
	}
	
	// inner class for the timing event
	public class ClockListener implements ActionListener
	{
		public void actionPerformed(ActionEvent evt)
		{
			try
			{
				String lookupName = "rmi://rees.uwaterloo.ca:" + m_connectPort + "/IServer";

				// attempt to connect to the other server
				m_peerServer = (IServer)Naming.lookup(lookupName);

				m_peerAlive = m_peerServer.areYouAlive();
				
				System.out.println(getCurrTime() + " My peer is alive!");

				// TODO: only want to send info if the m_stateChanged == true
				if (m_mode.equals("primary"))
				{
					// notify the secondary server of the primary server's state
					m_peerServer.notifyChange("foo");
				}
			}
			catch (MalformedURLException murle)
			{
				System.err.println("murle: " + murle.getMessage());
				return;
			}
			catch (NotBoundException nbe)
			{
				System.err.println("nbe: " + nbe.getMessage());
				return;
			}
			catch (Exception e)
			{
				// assume that the secondary server has crashed
				// System.err.println(e.getMessage());
				System.err.println(getCurrTime() + " Other server has crashed.");
				m_peerAlive = false;
			}
		}
	}


	public static void main(String[] args)
	{
		Server1 myServer = null;

		if (args.length != 3)
		{
			System.out.println("Usage bindingPort connectPort [primary|secondary]");
			System.exit(-1);
		}

		int bindingPort = Integer.parseInt(args[0]);
		int connectPort = Integer.parseInt(args[1]);

		String mode = args[2];

		try
		{
			if (mode != null && mode.equals("primary"))
			{
				myServer = new Server1(bindingPort, connectPort, mode);
			}
			else
			{
				myServer = new Server1(bindingPort, connectPort, mode);
			}
		}	
		catch (Exception e)
		{
			System.err.println("main() e:" + e.getMessage());
		}
	} // main()
} // class Server1
